#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>

#include "acceptor.h"
#include "client_manager.h"

static uint32_t g_client_ip = 0x0A0A0A0B;

/* Read client message */
static void packet_read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
	char *buffer;
	ssize_t read_num;
	client_t *client = (client_t *)watcher;
	server_params_t *params = client->params;

	if (EV_ERROR & revents) {
		perror("packet_read_cb got invalid event");
		return;
	}

	buffer = packet_buffer_alloc();
	if (buffer == NULL) {
		return;
	}

	// Receive message from client socket
	read_num = recv(watcher->fd, buffer, BUFFER_SIZE, 0);
	if (read_num < 0) { // 出现错误
		perror("recv error");
		return;
	} else if (read_num == 0) { // 有client关闭时
		// Stop and free watcher if client socket is closing
		ev_io_stop(loop, watcher);
		client_return((client_t *)watcher);
		return;
	}

	// 有数据到来
	// plugin_printhex(buffer, read_num);
	
	if (read_num < sizeof(uint32_t)) {
		fprintf(stderr, "Invaild buffer len: %d\n", read_num);
		packet_buffer_return(buffer);
		return;
	} else if (read_num == (sizeof(uint32_t) * 2)) {
		uint32_t *ip = (uint32_t *)buffer;
		if (ip[0] == 0 && params->type == 1) { // 游戏服务收到客户端发来的ip
			char ipstr[20];
			printf("Game server recvd from ip(%p, %s) from client.\n", client, ip_to_str_ul(ntohl(ip[1]), ipstr));
			client->ip = ip[1];
			packet_buffer_return(buffer);
			return;
		}
	}

	// 广播数据，如果没有其他client，直接回收buffer，否则在广播完成后回收
	if (packet_broadcast(loop, (client_t *)watcher, buffer, read_num) == 0) {
		packet_buffer_return(buffer);
	}
}

// -----------------------------------------------------------

/* Accept client requests */
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);
	int client_sd;
	client_t *client;
	acceptor_t *acceptor = (acceptor_t *)watcher;
	server_params_t *params = acceptor->params;

	if (EV_ERROR & revents) {
		perror("accept_cb got invalid event");
		return;
	}

	// Accept client request
	client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);
	if (client_sd < 0) {
		perror("accept error");
		return;
	}

	client = client_alloc(params);
	if (client == NULL) {
		return;
	}

	if (params->type == 0) { // 协调服务分配IP，然后会下发到客户端
		client->ip = htonl(g_client_ip);
		g_client_ip++;
		char ipstr[20];
		printf("Coor server is connected by client(%p, %s).\n", client, ip_to_str_ul(ntohl(client->ip), ipstr));

		uint32_t buf[2];
		buf[0] = 0;
		buf[1] = client->ip;
		int send_num = send(client_sd, (const void *)buf, sizeof(buf), 0);
		if (send_num < 0) { // 有client关闭时
			perror("send error");
			client_return(client);
			return;
		}
		printf("Coor server sent new ip to client.\n");
	} else { // 游戏服务不分配IP，等待客户端上发之前协调服务分配的IP
		client->ip = 0;
		printf("Game Server is connected by client.\n");
	}

	// Initialize and start watcher to read client requests
	ev_io_init(&client->watcher, packet_read_cb, client_sd, EV_READ);
	ev_io_start(loop, &client->watcher);
}